#ifndef G3_RES_HANDLE_H
#define G3_RES_HANDLE_H

#include "log.h"
#include "types.h"

#include <time.h>

namespace G3 {

class RESOURCE_BASE {
	public:
		RESOURCE_BASE () {
			lock_count = 0;

			SetAccessed ();
		}

		virtual ~RESOURCE_BASE () {

		}

		int lock_count;
		time_t last_access;

		void SetAccessed () {
			last_access = time (NULL);
		}

//==============================================================================
// Lock manipulation
//==============================================================================
		void Lock () {
			lock_count++;
		}

		void UnLock () {
			lock_count--;
			if (lock_count < 0)
				lock_count = 0;
		}

		bool IsLocked () const {
			return (lock_count > 0);
		}

//==============================================================================
// Resource maintenance
//==============================================================================
		virtual long GetSize () = 0;
		virtual void Release () = 0;
		virtual bool Recreate () = 0;
		virtual void Clear () = 0;
};

template <class HType>
class HANDLE {
	enum {
		// Maximum number of bits
		MAX_INDEX_BITS = 16,
		MAX_MAGIC_BITS = 16,
		// Maximum values
		MAX_INDEX = (1 << MAX_INDEX_BITS) - 1,
		MAX_MAGIC = (1 << MAX_MAGIC_BITS) - 1
	};

	union {
		struct {
			uint bIndex : MAX_INDEX_BITS;
			uint bMagic : MAX_MAGIC_BITS;
		};

		uint Handle;
	};

	public:
		HANDLE () {
			Handle = 0;
			Log = &G3::MainLog;
		}

		HANDLE (uint handle) {
			Handle = handle;
			Log = &G3::MainLog;
		}

		G3::LOG *Log;

//==============================================================================
// Gives the handle an index
//==============================================================================
		bool Init (uint Index) {
			Assert (IsNull (), "HANDLE::Init: Trying to reassign a non-Null handle");
			Assert (Index <= MAX_INDEX, "HANDLE::Init: Index argument is too big");

			static uint MagicCount = 0;
			// Magic 0 is used for NULL handles
			if (++MagicCount > MAX_MAGIC)
				MagicCount = 1;

			bIndex = Index;
			bMagic = MagicCount;

			return true;
		}

		uint GetIndex () const { return bIndex; }
		uint GetMagic () const { return bMagic; }
		uint GetHandle () const { return Handle; }

		void SetNull () { bMagic = 0; }

		bool IsNull () const { return (!bMagic); }

		operator uint (void) const { return Handle; }

		HANDLE<HType>& operator= (const HANDLE<HType> &h) {
			Handle = h.Handle;

			return *this;
		}

		bool operator== (const HANDLE<HType> &h) const {
			return (Handle == h.Handle);
		}

		bool operator== (const uint &h) const {
			return (Handle == h);
		}

		bool operator!= (const HANDLE<HType> &h) const {
			return (Handle != h.Handle);
		}
};

}

#endif
